﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using static Debugger;

namespace Module.FlowChart.Model
{
    internal sealed class Document
    {

        const byte FileStartFlag = 110;//文件开始标志
        const byte FileEndFlag = 120;//文件结束标志
        const int MaxPage = 100;
        public const string DocExtension = ".FC";//扩展名

        bool m_Changed;//表示距离上次保存文件是否被修改过

        List<WorkPage> m_WorkPages;

        public string Path = "";
        public string DocName = "";//文件名称,不含扩展名
        public string AuthorName = "";//作者姓名

        public string FullName => DocName + DocExtension;//文件全称,含扩展名

        public List<WorkPage> WorkPages => new List<WorkPage>(m_WorkPages);
        public WorkPage CurrentWorkPage { get; private set; }

        static Document()
        {
            Assembly assembly = typeof(Document).Assembly;
            string ns = typeof(Document).Namespace;
            foreach (var type in assembly.GetTypes())
            {
                if (type.Namespace == ns &&
                    typeof(WorkPage).IsAssignableFrom(type) &&
                    typeof(WorkPage) != type)
                {
                    type.GetMethod("StaticInit", BindingFlags.Static | BindingFlags.NonPublic)?.Invoke(null, null);
                }
            }
        }
        public Document(bool creatonepage = false)
        {
            m_WorkPages = new List<WorkPage>();
            Assert(WorkPage.WorkPageCreators.Keys.Count > 0);
            if (!creatonepage)
            {
                return;
            }
            CreatWorkPage(WorkPage.DefaultPageType,
                WorkPage.WorkPageNameCreator[WorkPage.DefaultPageType](1));
        }

        public bool GetIsChanged()
        {
            if (m_Changed)
                return true;
            for (int i = 0; i < m_WorkPages.Count; i++)
                if (m_WorkPages[i] != null && m_WorkPages[i].IsChanged)
                    return true;
            return false;
        }
        public bool Save(string path)
        {
            throw new NotImplementedException();
        }
        public bool Save(BinaryWriter bw)
        {
            bw.Write(FileStartFlag);

            bw.Write(AuthorName);
            bw.Write(m_WorkPages.Count);
            foreach (var book in m_WorkPages)
                book.Save(bw);

            bw.Write(FileEndFlag);
            return true;
        }
        public WorkPage CreatWorkPage(string typename, string pagename = null)
        {
            if (m_WorkPages.Count >= MaxPage)
                return null;
            Assert(WorkPage.WorkPageCreators.ContainsKey(typename));
            if (pagename == null || pagename == "")
            {
                for (int i = 1; i < MaxPage + 5; i++)
                {
                    string name = WorkPage.WorkPageNameCreator[typename](i);
                    if (!HasPage(name))
                    {
                        pagename = name;
                        break;
                    }
                }
            }
            else
            {
                Assert(!HasPage(pagename));
            }
            Assert(pagename != "" && pagename != null);
            var page = WorkPage.WorkPageCreators[typename](pagename);
            page.Owner = this;
            m_WorkPages.Add(page);
            //SetCurrentWorkPage(pagename);
            return page;
        }

        /// <summary>
        /// 设置当前活跃的工作页
        /// </summary>
        /// <returns>true 成功 false 失败</returns>
        public bool SetCurrentWorkPage(string name)
        {
            foreach (var item in WorkPages)
            {
                if (item.Name == name)
                {
                    CurrentWorkPage = item;
                    return true;
                }
            }
            return false;
        }

        public bool RemovePage(string name)
        {
            if (m_WorkPages.Count <= 1)
                return false;
            int index = m_WorkPages.FindIndex((p) => p.Name == name);
            if (index < 0)
                return false;
            m_WorkPages.RemoveAt(index);
            return true;
        }

        /// <summary>
        /// 是否存在指定名称的页
        /// </summary>
        /// <returns>true 有 false 无</returns>
        public bool HasPage(string name)
        {
            foreach (var item in WorkPages)
            {
                if (item.Name == name)
                {
                    return true;
                }
            }
            return false;
        }

        public WorkPage TryGetPage(string name)
        {
            foreach (var item in WorkPages)
            {
                if (item.Name == name)
                {
                    return item;
                }
            }
            return null;
        }
        public bool MoveUp(string name)
        {
            int index = m_WorkPages.FindIndex((p) => p.Name == name);
            if (index > 0 && index < m_WorkPages.Count)
            {
                var t = m_WorkPages[index - 1];
                m_WorkPages[index - 1] = m_WorkPages[index];
                m_WorkPages[index] = t;
                return true;
            }
            return false;
        }
        public bool MoveDown(string name)
        {
            int index = m_WorkPages.FindIndex((p) => p.Name == name);
            if (index >= 0 && index < m_WorkPages.Count - 1)
            {
                var t = m_WorkPages[index + 1];
                m_WorkPages[index + 1] = m_WorkPages[index];
                m_WorkPages[index] = t;
                return true;
            }
            return false;
        }
        public static Document LoadFromFile(string path)
        {
            throw new NotImplementedException();
        }
        public static Document LoadFromBytes(BinaryReader br, Document doc = null)
        {
            if (doc == null)
                doc = new Document();

            if (br.ReadByte() != FileStartFlag)
                throw new Exception("Unexpected start");

            doc.AuthorName = br.ReadString();

            int c = br.ReadInt32();
            for (int i = 0; i < c; i++)
            {
                var wp = WorkPage.WorkPageLoaders[br.ReadString()](br);
                wp.Owner = doc;
                doc.m_WorkPages.Add(wp);
            }
            Assert(doc.m_WorkPages.Count > 0);
            doc.CurrentWorkPage = doc.m_WorkPages[0];

            if (br.ReadByte() != FileEndFlag)
                throw new Exception("Unexpected end");
            return doc;
        }

    }

}

